package gnss

import (
	"dgo/goutils/gis"
	"dgo/goutils/utils"
	"fmt"
	"time"
)

type VrsDataChecker struct {
	epochDe      *GnssSVEpochRtcmDecoder
	lastEpoch    *GnssSVEpoch
	lastEpochT   time.Time
	lastEpochTOW uint32
	Id           string
	ntripcltConf string

	stationID    uint16
	sta1005      *GnssStation
	disLastWarnT time.Time
	rtcmInfo     string

	epochCnt         int32
	epochAbnormalCnt int32
	crcFailCnt       int32
	delayCnt         int32
	sta1005ChangCnt  int32
	dis              float64

	OnAfterCheckEpoch func(abnormal byte)
	OnOutputMsg       func(s string, args ...interface{})

	Bd3_check byte
	Qzs_check byte
	Glo_check byte
	Gal_check byte
	B1c_check byte
	B2a_check byte

	bd3_flag byte
	glo_flag byte
	gal_flag byte
	gps_flag byte
	bd2_flag byte
	qzs_flag byte
	b2a_flag byte
	b1c_flag byte

	StartGpsTime time.Time

	// 超过该值认为不正常, 默认3s, <0 不检测
	CheckRtcmDelaySecs float64

	// 测站位置
	RoverB, RoverL, RoverH float64

	rtcmDec *Rtcm3RawBufDecoder
}

func NewVrsDataChecker() *VrsDataChecker {
	rval := &VrsDataChecker{}
	rval.CheckRtcmDelaySecs = 3
	rval.Bd3_check = 1
	rval.B2a_check = 1
	rval.B1c_check = 1
	rval.Gal_check = 1
	rval.Glo_check = 1
	return rval
}

func (sess *VrsDataChecker) RtcmInfo() string {
	return sess.rtcmInfo
}

func (sess *VrsDataChecker) SetRoverBlh(b, l, h float64) {
	sess.RoverB = b
	sess.RoverL = l
	sess.RoverH = h

}

func (sess *VrsDataChecker) Status() string {
	return fmt.Sprintf("历元:%d, 异常历元:%d, crc失败:%d", sess.epochCnt, sess.epochAbnormalCnt, sess.crcFailCnt)
}

func (sess *VrsDataChecker) AbnormalStatus() string {
	var sb utils.BytesBuilder
	if sess.TidyAbnormal(&sb) > 0 {
		return sb.String()
	}
	return ""
}

/*
*

	在收到一个历元后进行检测
*/
func (sess *VrsDataChecker) checkAbnormal(sb *utils.BytesBuilder) (cnt int) {
	if sess.CheckRtcmDelaySecs > 0 && !sess.lastEpochT.IsZero() {
		delaysecs := RTKGPSDelaySecs(sess.lastEpochT)
		if delaysecs > sess.CheckRtcmDelaySecs {
			sb.Appendf("数据延迟%.0fs,", delaysecs)
			cnt++
		}
	}

	if sess.Bd3_check == 1 {
		if sess.bd3_flag == 0 {
			sb.Appendf("缺少没有BD3卫星,")
			cnt++
		}
		if sess.b1c_flag == 0 && sess.B1c_check == 1 {
			sb.Appendf("缺少B1C频点,")
			cnt++
		}
		if sess.b2a_flag == 0 && sess.B2a_check == 1 {
			sb.Appendf("缺少B2a频点,")
			cnt++
		}
	}

	if sess.Gal_check == 1 {
		if sess.gal_flag == 0 {
			sb.Appendf("缺少Gal卫星,")
			cnt++
		}
	}

	if sess.Glo_check == 1 {
		if sess.glo_flag == 0 {
			sb.Appendf("缺少Glo卫星,")
			cnt++
		}
	}

	if sess.Qzs_check == 1 {
		if sess.qzs_flag == 0 {
			sb.Appendf("缺少QZS卫星,")
			cnt++
		}
	}

	if sess.bd2_flag == 0 {
		sb.Appendf("缺少BDS卫星,")
		cnt++
	}

	if sess.gps_flag == 0 {
		sb.Appendf("缺少GPS卫星,")
		cnt++
	}

	return cnt
}

func (sess *VrsDataChecker) StationID() uint16 {
	return sess.stationID
}

func (sess *VrsDataChecker) TidyAbnormal(sb *utils.BytesBuilder) (cnt int) {
	if len(sess.Id) > 0 {
		sb.Appendf("%s:", sess.Id)
	}

	if sess.lastEpochT.IsZero() {
		sb.AppendIfNotEmpty(",").Appendf("缺少观测数据")
		cnt++
	} else {

		cnt += sess.checkAbnormal(sb)
		if sess.epochAbnormalCnt > 0 {
			sb.AppendIfNotEmpty(",").Appendf("历元异常次数:%d", sess.epochAbnormalCnt)
			cnt++
		}

		if sess.sta1005ChangCnt > 0 {
			sb.AppendIfNotEmpty(",").Appendf("基站信息变化次数:%d,", sess.sta1005ChangCnt)
			cnt++
		}
	}

	if sess.dis > 5000 {
		sb.AppendIfNotEmpty(",").Appendf("距离虚拟基站过远:%.0f(M),", sess.dis)
		cnt++
	}
	sb.AppendIfNotEmpty(",").Appendf("历元总数:%d", sess.epochCnt)
	sb.AppendStr("\r\n")
	return
}

func (this *VrsDataChecker) RtcmDelaySecs() float64 {
	if this.lastEpoch == nil {
		return -1
	} else {
		return utils.Round64(RTKGPSDelaySecs(this.lastEpoch.GetGpsTime(utils.ZeroTime)), 2)
	}
}

func (this *VrsDataChecker) BaseSiteBlh() (b, l, h float64) {
	sta := this.sta1005
	if sta == nil {
		return
	}
	b, l, h = gis.EcefXyz2PosiLatLngH(sta.Pos[0], sta.Pos[1], sta.Pos[2])
	return
}

func (this *VrsDataChecker) BaseSiteXyz() string {
	if this.sta1005 == nil {
		return ""
	}
	return fmt.Sprintf("%.4f %.4f %.4f", this.sta1005.Pos[0], this.sta1005.Pos[1], this.sta1005.Pos[2])
}

func (this *VrsDataChecker) BaseSiteDis(b0, l0 float64) float64 {
	sta := this.sta1005
	b, l, _ := gis.EcefXyz2PosiLatLngH(sta.Pos[0], sta.Pos[1], sta.Pos[2])
	if b0 != 0 && l0 != 0 {
		return utils.Round64(gis.CalcuDis(l, b, l0, b0), 2)
	}
	return -1
}

func (this *VrsDataChecker) checkSignal(epoch *GnssSVEpoch) {
	var b2aflag, b1cflag byte
	var gloflag, bd2flag, bd3flag, galflag, gpsflag, qzsflag byte
	epoch.StatSignalEx(func(navisys byte, singaltext string, singalstr string, signalid byte, flag byte) {
		if navisys == SYS_BD {
			if flag == 2 {
				bd2flag = 1
			} else if flag == 3 {
				bd3flag = 1
				if signalid == GNSS_SV_SIG_BDS_B2a_5D || signalid == GNSS_SV_SIG_BDS_B2a_5P {
					b2aflag = 1
				} else if signalid == GNSS_SV_SIG_BDS_B1C_1P || signalid == GNSS_SV_SIG_BDS_B1C_1D {
					b1cflag = 1
				}
			}
		} else if navisys == SYS_GLO {
			gloflag = 1
		} else if navisys == SYS_GAL {
			galflag = 1
		} else if navisys == SYS_GPS {
			gpsflag = 1
		} else if navisys == SYS_QZS {
			qzsflag = 1

		}
	})
	this.b2a_flag = b2aflag
	this.b1c_flag = b1cflag
	this.bd3_flag = bd3flag
	this.bd2_flag = bd2flag
	this.glo_flag = gloflag
	this.gal_flag = galflag
	this.gps_flag = gpsflag
	this.qzs_flag = qzsflag
}

func (this *VrsDataChecker) onMsg(s string, args ...interface{}) {
	if this.OnOutputMsg != nil {
		this.OnOutputMsg(s, args...)
	} else {
		utils.Log.Warnf(s, args...)
	}
}

func (this *VrsDataChecker) InputBuf(buf []byte) {
	if this.rtcmDec == nil {
		this.rtcmDec = NewRtcm32RawBufDecoder("VrsDataChecker")
		this.rtcmDec.OnRtcmBuf = this.InputRtcmBuf
		this.rtcmDec.OnErr = func(errcode int, err error) bool {
			this.crcFailCnt++
			this.onMsg("rtcm dec err:%s", err.Error())
			return true
		}
	}

	this.rtcmDec.InputBuf(buf)
}

func (this *VrsDataChecker) InputRtcmBuf(buf []byte) {
	var rtcmT time.Time
	if this.epochDe == nil {
		this.epochDe = NewGnssSVEpochRtcmDecoder()
		this.epochDe.OnSignConvert = OnSingalConvertFromRtcm
		this.epochDe.OnEpochFunc = func(epoch *GnssSVEpoch, checktype int) {
			this.epochCnt++
			cpyEpoch := NewGnssSVEpoch()
			cpyEpoch.CopyFrom(epoch)
			if this.stationID != 0 && cpyEpoch.StaID != this.stationID {
				this.onMsg("[%s]基站ID变化[%d->%d]", this.Id, this.stationID, cpyEpoch.StaID)
				this.sta1005ChangCnt++
			}
			this.stationID = cpyEpoch.StaID
			this.rtcmInfo = fmt.Sprintf("%s,%s", cpyEpoch.StatSatNum(), cpyEpoch.StatSignal())
			this.checkSignal(epoch)

			if this.StartGpsTime.IsZero() {
				rtcmT = cpyEpoch.GetGpsTime(utils.ZeroTime)
			} else {
				reft := this.StartGpsTime
				if !this.lastEpochT.IsZero() {
					reft = this.lastEpochT
				}
				rtcmT = cpyEpoch.GetGpsTime(reft)
			}

			// this.onMsg("[%s]当前历元：%s[%d]", this.Id, utils.DateTimeString2(rtcmT), cpyEpoch.TOW)
			abnormalflag := U8_0

			if this.CheckRtcmDelaySecs > 0 && !rtcmT.IsZero() {
				delaysec := RTKGPSDelaySecs(rtcmT)
				if delaysec > this.CheckRtcmDelaySecs {
					this.onMsg("[%s][%s]数据延迟:%.2f(s)", this.Id, utils.DateTimeString2(rtcmT), delaysec)
					this.delayCnt++
					abnormalflag = 1
				}
			}

			if this.lastEpoch != nil {
				t0 := this.lastEpochT.Add(time.Second)
				if this.lastEpochT == rtcmT {
					this.onMsg("[%s]历元重复%s[%d]", this.Id, utils.DateTimeString2(rtcmT), cpyEpoch.TOW)
					abnormalflag = 1
				} else if t0 != rtcmT {
					this.onMsg("[%s]缺失历元,上一个历元:%s[%s][%d], 当前历元：%s[%d]", this.Id,
						utils.DateTimeString2(this.lastEpoch.GetGpsTime(time.Now().UTC())), utils.DateTimeString3(this.lastEpochT), this.lastEpochTOW,
						utils.DateTimeString2(rtcmT), cpyEpoch.TOW)
					abnormalflag = 1
				}
			}

			var sb utils.BytesBuilder
			if this.checkAbnormal(&sb) > 0 && abnormalflag == 0 {
				this.onMsg("[%s]异常, 当前历元：%s[%d], :%s", this.Id, utils.DateTimeString2(rtcmT), cpyEpoch.TOW, sb.String())
				abnormalflag = 1
			}

			if this.lastEpoch != nil && abnormalflag == 0 {
				eflag := 0
				cpyEpoch.CompareFunc(this.lastEpoch, func(obs_m, obs_s *GnssSVObs, sig_m, sig_s *GnssSVSignal) bool {
					if sig_m != nil && sig_s != nil {
						if sig_m.PsV == sig_s.PsV {
							this.onMsg("[%s]观测值与前一个历元伪距相同[%s]%s %s:%.4f", this.Id, obs_m.GetPrnCode(), utils.DateTimeString2(rtcmT), sig_m.GetSignalCode(), sig_m.PsV)
							eflag = 1
						} else if sig_m.PhV == sig_s.PhV {
							this.onMsg("[%s]观测值与前一个历元相位相同[%s]%s %s:%.4f", this.Id, obs_m.GetPrnCode(), utils.DateTimeString2(rtcmT), sig_m.GetSignalCode(), sig_m.PhV)
							eflag = 1
						}
					}
					return true
				})
				if eflag == 1 {
					abnormalflag = 1
				}
			}

			if abnormalflag == 1 {
				this.epochAbnormalCnt++
			}

			if this.OnAfterCheckEpoch != nil {
				this.OnAfterCheckEpoch(abnormalflag)
			}

			this.lastEpoch = cpyEpoch
			this.lastEpochT = rtcmT
			this.lastEpochTOW = cpyEpoch.TOW

		}
		this.epochDe.OnRtcmCrcFail = func(buf []byte, err error) {
			this.onMsg("[%s]基站数据CRC异常", this.Id)
		}
		this.epochDe.OnRtcmBuf = func(msgid uint16, buf []byte) bool {
			if msgid == 1005 || msgid == 1006 {
				sta := &GnssStation{}
				DecodeRtcm1005V1(sta, buf, 24)
				if this.stationID != 0 && sta.StationId != this.stationID {
					this.onMsg("[%s]基站ID变化[%d->%d]", this.Id, this.stationID, sta.StationId)
					this.sta1005ChangCnt++
				}
				this.stationID = sta.StationId

				if this.sta1005 == nil {
					this.sta1005 = sta
				} else {
					if sta.Pos[0] != this.sta1005.Pos[0] || sta.Pos[1] != this.sta1005.Pos[1] || sta.Pos[2] != this.sta1005.Pos[2] {
						this.onMsg("[%s]基站坐标变化[%.4f %.4f %.4f->%.4f %.4f %.4f]", this.Id,
							this.sta1005.Pos[0], this.sta1005.Pos[1], this.sta1005.Pos[2], sta.Pos[0], sta.Pos[1], sta.Pos[2])
						this.sta1005ChangCnt++
					}
					this.sta1005 = sta
				}

				if this.RoverB != 0 {
					dis := this.BaseSiteDis(this.RoverB, this.RoverL)
					this.dis = dis
					if dis != -1 && dis > 5000 {
						if this.disLastWarnT.IsZero() || time.Since(this.disLastWarnT).Seconds() > 10 {
							this.onMsg("[%s]距离基站太远(%.2f)M", this.Id, dis)
						}
					}
				}

			}
			return true
		}
	}

	this.epochDe.InputBuf(buf)

}
